package org.zero.onlinesubject.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mysql.cj.util.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zero.onlinesubject.common.vo.HomeworkVo;
import org.zero.onlinesubject.common.vo.components.*;
import org.zero.onlinesubject.entity.Course;
import org.zero.onlinesubject.entity.Homework;
import org.zero.onlinesubject.entity.HomeworkTemplate;
import org.zero.onlinesubject.entity.User;
import org.zero.onlinesubject.mapper.CourseMapper;
import org.zero.onlinesubject.mapper.HomeworkMapper;
import org.zero.onlinesubject.mapper.HomeworkTemplateMapper;
import org.zero.onlinesubject.mapper.UserMapper;
import org.zero.onlinesubject.service.HomeworkService;
import org.zero.onlinesubject.service.HomeworkTemplateService;
import org.zero.onlinesubject.utils.UserContextHolder;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.*;

/**
 *
 */
@Service
public class HomeworkServiceImpl extends ServiceImpl<HomeworkMapper, Homework>
    implements HomeworkService {

    @Resource
    private HomeworkMapper homeworkMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private CourseMapper courseMapper;

    @Resource
    private ThreadService threadService;

    @Resource
    private Executor taskExecutor;

    @Override
    public HomeworkVo getHomeworkVo(Integer homeworkId) throws ExecutionException, InterruptedException, TimeoutException {
        Homework homework = homeworkMapper.selectById(homeworkId);
        HomeworkVo vo = new HomeworkVo();
        copyProperty(homework,vo);
        return vo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean deleteHomework(Integer homeworkId) {
        Homework homework = getById(homeworkId);

        // 判断是不是作业的发布者
         String userId = UserContextHolder.get().getUserid();
         if(!userId.equals(homework.getSenderId())){
             log.error("当前用户没有删除权限");
             return false;
         }
        Boolean flag = removeById(homeworkId);
        QueryWrapper<Homework> wrapper = new QueryWrapper<>();
        wrapper.eq("FromCode",homeworkId);
        Boolean flag2 = remove(wrapper);
        return flag && flag2;
    }

    @Override
    public Boolean updateHomework(HomeworkVo homeworkVo) {
        List<SingleSelect> singleList = homeworkVo.getSingleList();
        List<MultiSelect> multiList = homeworkVo.getMultiList();
        List<FillBlank> fillBlankList = homeworkVo.getFillBlankList();
        List<ShortAnswerQuestion> answerList = homeworkVo.getShortAnswerList();

        singleList.forEach(item->{
            if(!StringUtils.isNullOrEmpty(item.getChoice())){
                item.setIsDone(true);
            }
        });
        multiList.forEach(item->{
            boolean flag = false;
            for (Node node : item.getNodes()) {
                if (node.getIsSelect()) {
                    flag = true;
                    break;
                }
            }
            if(flag){
                item.setIsDone(true);
            }
        });
        fillBlankList.forEach(item->{
            if(!StringUtils.isNullOrEmpty(item.getAnswer())){
                item.setIsDone(true);
            }
        });
        answerList.forEach(item->{
            if(!StringUtils.isNullOrEmpty(item.getAnswer())){
                item.setIsDone(true);
            }
        });

        // 只有老师和学生本人可以修改
        Homework homework = new Homework();
        homeworkVo.setIsFinished(true);
        homework.setIsFinished(true);
        fromVoToObj(homeworkVo,homework);
        homework.setId(homeworkVo.getId());
        return homeworkMapper.updateById(homework)!=0;
    }

    public void copyProperty(Homework homework,HomeworkVo homeworkVo) throws ExecutionException, InterruptedException, TimeoutException {
        homeworkVo.setId(homework.getId());
        homeworkVo.setName(homework.getName());
        CompletableFuture<User> f1 = CompletableFuture.supplyAsync(() -> {
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.select("UserName").eq("UserID", homework.getSenderId()).last(" limit 1");
            return userMapper.selectOne(wrapper);
        },taskExecutor);
        CompletableFuture<Course> f2 = CompletableFuture.supplyAsync(() -> {
            QueryWrapper<Course> wrapper = new QueryWrapper<>();
            wrapper.select("CourseName").eq("CourseID", homework.getCourseId()).last(" limit 1");
            return courseMapper.selectOne(wrapper);
        }, taskExecutor);
        homeworkVo.setFromCode(homework.getFromcode());
        homeworkVo.setClassId(homework.getClassId());
        homeworkVo.setPubTime(homework.getPubTime());
        homeworkVo.setFinishTime(homework.getFinishTime());
        homeworkVo.setApprovalState(homework.getApprovalState());
        homeworkVo.setIsFinished(homework.getIsFinished());
        homeworkVo.setSingleList(JSON.parseObject(homework.getSingleList(),new TypeReference<List<SingleSelect>>(){}));
        homeworkVo.setMultiList(JSON.parseObject(homework.getMultiList(),new TypeReference<List<MultiSelect>>(){}));
        homeworkVo.setFillBlankList(JSON.parseObject(homework.getFillBlankList(),new TypeReference<List<FillBlank>>(){}));
        homeworkVo.setShortAnswerList(JSON.parseObject(homework.getShortAnswerList(),new TypeReference<List<ShortAnswerQuestion>>(){}));

        homeworkVo.setQuestionCount(homework.getQuestionCount());
        homeworkVo.setTotalScore(homework.getScore());
        User user = f1.get(3, TimeUnit.SECONDS);
        Course course = f2.get(3, TimeUnit.SECONDS);
        homeworkVo.setSender(user.getUsername());
        homeworkVo.setCourseId(homework.getCourseId());
        homeworkVo.setCourseName(course.getCoursename());
    }

    public void fromVoToObj(HomeworkVo homeworkVo, Homework homework){
        homework.setName(homeworkVo.getName());
        homework.setRecevieId(homeworkVo.getRecevier());
        homework.setClassId(homeworkVo.getClassId());
        User user = UserContextHolder.get();
        String userId = user.getUserid();
        if(user.getRoleid() == 3){
            homework.setSenderId(userId);
            homeworkVo.setSender(userId);
        }else{
            homework.setRecevieId(userId);
        }

        if (homeworkVo.getIsFinished()) {
            homework.setFinishTime(LocalDateTime.now());
        }
        homework.setSingleList(JSON.toJSONString(homeworkVo.getSingleList()));
        homework.setMultiList(JSON.toJSONString(homeworkVo.getMultiList()));
        homework.setFillBlankList(JSON.toJSONString(homeworkVo.getFillBlankList()));
        homework.setShortAnswerList(JSON.toJSONString(homeworkVo.getShortAnswerList()));

        homework.setCourseId(homeworkVo.getCourseId());
        homework.setIsFinished(homeworkVo.getIsFinished());
        homework.setScore(homeworkVo.getTotalScore());
        homework.setQuestionCount(homeworkVo.getQuestionCount());
        homework.setPubTime(homeworkVo.getPubTime());
        if(!StringUtils.isNullOrEmpty(homeworkVo.getApprovalState())){
            homework.setApprovalState(homeworkVo.getApprovalState());
        }
    }

    @Override
    public Boolean createHomework(HomeworkVo homeworkVo) throws ExecutionException, InterruptedException, TimeoutException {
        Homework homework = new Homework();
        homeworkVo.setPubTime(LocalDateTime.now());
        homeworkVo.setApprovalState("0000");
        fromVoToObj(homeworkVo,homework);

        Boolean flag = homeworkMapper.insertOne(homework)!=0;
        if(flag){
            homeworkVo.setId(homework.getId());
            threadService.dispatchHomework(homeworkVo,homeworkMapper,userMapper);
        }
        return flag;
    }

    @Override
    public List<Homework> getHomeworkList(String userId, Integer current, Integer size) {
        QueryWrapper<Homework> wrapper = new QueryWrapper<>();
        wrapper.select("ID","FromCode","Name","SenderID","CourseID","RecevieID","IsFinished","PubTime","FinishTime").eq("RecevieID",userId).last(" limit "+current+","+size);
        return homeworkMapper.selectList(wrapper);
    }

    @Override
    public List<Homework> getPubList(String userId, Integer current, Integer size) {
        QueryWrapper<Homework> wrapper = new QueryWrapper<>();
        wrapper.select("ID","FromCode","Name","CourseID","RecevieID","IsFinished","PubTime","FinishTime")
                .eq("SenderID",userId)
                .isNull("FromCode")
                .last(" limit "+current+","+size);
        return homeworkMapper.selectList(wrapper);
    }

    @Override
    public List<HomeworkVo> getApprovalList(String classId, String courseId, String approval, Integer current, Integer size) {
        String userId = UserContextHolder.get().getUserid();
        List<HomeworkVo> voList = homeworkMapper.getApprovalList(userId,classId,courseId,approval,current,size);
        return voList;
    }

    @Override
    public Double calcScore(HomeworkVo homeworkVo){
        Integer code = homeworkVo.getFromCode();
        Homework obj = homeworkMapper.selectById(code);
        String singleJson = obj.getSingleList();
        String multiJson = obj.getMultiList();
        List<FillBlank> blankList = homeworkVo.getFillBlankList();
        List<ShortAnswerQuestion> answerList = homeworkVo.getShortAnswerList();

        List<SingleSelect> singleResList = JSON.parseObject(singleJson, new TypeReference<List<SingleSelect>>() {
        });
        List<MultiSelect> multiResList = JSON.parseObject(multiJson, new TypeReference<List<MultiSelect>>() {
        });

        List<SingleSelect> singleList = homeworkVo.getSingleList();
        List<MultiSelect> multiList = homeworkVo.getMultiList();

        Iterator<SingleSelect> resItr = singleResList.iterator();
        Iterator<SingleSelect> itra = singleList.iterator();
        Iterator<MultiSelect> multiResItra = multiResList.iterator();
        Iterator<MultiSelect> multiItra = multiList.iterator();
        Double[] scores = new Double[]{(double) 0};
        for (int i = 0; i < singleList.size(); i++) {
            SingleSelect res = resItr.next();
            SingleSelect select = itra.next();
            select.setScores(scores);
            if (res.getChoice().equals(select.getChoice())) {
                select.setScores(res.getScores());
            }

        }
        for (int i = 0; i < multiList.size(); i++) {
            MultiSelect multiRes = multiResItra.next();
            MultiSelect multiSelect = multiItra.next();

            Node[] resNode = multiRes.getNodes();
            Node[] multiNode = multiSelect.getNodes();
            boolean flag = true;
            for (int i1 = 0; i1 < multiNode.length; i1++) {
                if (resNode[i1].getIsSelect() != multiNode[i1].getIsSelect()) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                multiSelect.setScores(multiRes.getScores());
            }else{
                multiSelect.setScores(scores);
            }
        }
        Double totalScore = Double.valueOf(0);
        for (SingleSelect item : singleList) {
            totalScore += item.getScores()[0];
        }
        for (MultiSelect item : multiList) {
            for (Double score : item.getScores()) {
                totalScore += score;
            }
        }
        for (FillBlank item : blankList) {
            totalScore += item.getScores()[0];
        }
        for (ShortAnswerQuestion item : answerList) {
            totalScore += item.getScores()[0];
        }

        Homework homework = new Homework();
        homework.setId(homeworkVo.getId());
        fromVoToObj(homeworkVo,homework);
        homework.setScore(totalScore);
        homework.setApprovalState("9999");
        int rows = homeworkMapper.updateById(homework);
        if(rows!=0){
            return totalScore;
        }else{
            return null;
        }
    }
}




